import pygame
import time
import os
import random

#global variables
health_count = 10


#renders new images and stores them in a library
_images = {}
def get_image(path):
	global _images
	image = _images.get(path)
	
	if image == None:
		new_path = path.replace('/', os.sep).replace('\\', os.sep)
		image = pygame.image.load(new_path)
		_images[path] = image
	return image

#reads a file
def read_file(path):
	path = path.replace('/', os.sep).replace('\\', os.sep)
	new_file = open(path, 'rt')
	text = new_file.read()
	new_file.close()
	return text

#loads and caches text
_fonts = {}
_text = {}
def get_text(text, size, color):
	global _fonts, _text
	font_key = str(size)
	font = _fonts.get(font_key)
	if font == None:
		font = pygame.font.SysFont(pygame.font.get_default_font(), size)
		_fonts[font_key] = font
	image_key = font_key + "|" + str(size) + "|" + str(color) + "|" + text
	image = _text.get(image_key)
	if image == None:
		image = font.render(text, True, color)
		_text[image_key] = image
	
	return image



#Battle Scene
class BattleScene:
	def __init__(self):
		self.next = self
		self.counter = 0
		self.rand = True
		self.enemy_value = True
		self.enemy_x = 2134124
		self.enemy_y = 123481234
		self.color = 'blue'
		self.enemy_rand = random.randint(150, 200)
		self.death_count = 0



	def update(self):
		self.counter += 1

	def process_input(self, events):
		self.px = 35938
		self.py = 23429
		for event in events:
			if event.type == pygame.MOUSEBUTTONDOWN:
				self.px = event.pos[0]
				self.py = event.pos[1]
				
	def render(self, screen):              
		image = get_image('images/fight.png')
		image2 = get_image('images/fight2.png')
		background = get_image('images/fightbackground.png')
		self.kablam = get_image('images/kablam.png')
		death_render = get_text(str(self.death_count), 36, (255, 255, 255))
		screen.blit(death_render, (screen.get_width() / 2 - death_render.get_width() / 2, 20))
		health_render = get_text('Health: ' + str(health_count), 36, (255, 0, 0))
		screen.blit(health_render, (440, 20))

		#Checks if enemy needs to be rendered still
		def check_enemy_death (screen):
			
			if self.px >= self.enemy_x and self.px <= self.enemy_x + 60:
				if self.py >= self.enemy_y and self.py <= self.enemy_y + 60:
				       screen.blit(self.kablam, (self.enemy_x, self.enemy_y))
				       self.death_count += 1
				       if self.death_count == 8:
					       self.next = PlayScene()
				return True
			return False

		#Creates enemy and times how long enemies stay
		def create_enemy (screen, enemy_rand):
			

			iteration = 0
			if ( self.counter / enemy_rand ) % 2 == 0:

				iteration += 1

				if self.counter > enemy_rand:
					global health_count
					health_count -= 1
					self.counter = 0

				if self.rand == True:
					self.enemy_x = random.randint(0, 600)
					self.enemy_y = random.randint(0, 440)


				if self.enemy_value == True:

					color_list = {0: 'black',1: 'blue',2: 'grey',3: 'red'}
					number = str(random.randint(0,1))
					color_number = random.randint(0,3)
					if self.rand == True:
						self.color = color_list.get(color_number)
					enemy = get_image('images/bandit-' + self.color + '-shooting' + number +'.png')
					
					screen.blit(enemy, (self.enemy_x, self.enemy_y))
				return False
			else:
				return True

		if self.rand == True:
			screen.blit(background, (0,0))
			
		self.death = check_enemy_death (screen)

		if self.death == True:
			self.rand = True

		if self.death == False:
			create_enemy (screen, self.enemy_rand)
			self.rand = False


#Start screen
class TitleScene:
	def __init__(self):
		self.next = self
		self.counter = 0
	
	def process_input(self, events):
		for event in events:
			if event.type == pygame.KEYDOWN:
				if event.key == pygame.K_RETURN:
					self.next = PlayScene()
	
	def update(self):
		self.counter += 1
	
	def render(self, screen):
		background = get_image('images/town.png')
		screen.blit(background, (0, 0))
		instructions = get_text("Press enter to begin", 40, (0, 0, 0))	
		if (self.counter / 15) % 2 == 0:
			screen.blit(instructions, (325, 435))

#pause screen and caches the main game screen
class PauseScene:
	def __init__(self, play_scene):
		self.next = self
		self.play_scene = play_scene
		self.overlay = None
	
	def process_input(self, events):
		for event in events:
			if event.type == pygame.KEYDOWN:
				if event.key == pygame.K_RETURN:
					self.next = self.play_scene
					self.next.next = self.next
	
	def update(self):
		pass
	
	def render(self, screen):
		self.play_scene.render(screen)
		if self.overlay == None:
			self.overlay = pygame.Surface((screen.get_width(), screen.get_height()), pygame.SRCALPHA)
			self.overlay.fill((0, 0, 0, 128))
		
		screen.blit(self.overlay, (0, 0))
		pause_text = get_text("Paused", 32, (255, 255, 255))
		screen.blit(pause_text, (screen.get_width() / 2 - pause_text.get_width() / 2, screen.get_height() / 2 - pause_text.get_height()))
		health_render = get_text('Health: ' + str(health_count), 36, (255, 0, 0))

#The part of the game you actually play wheeeeee :D
class PlayScene:
	def __init__(self):

		self.next = self
		self.col = 7
		self.row = 7
		self.map_key = str(self.row) + '_' + str(self.col)
		self.initialize('maps/level_' + self.map_key + '.txt')
		self.counter = 0
		self.player_direction = 'down'
		self.walking = False
		self.keys_pressed = {
			'left': False,
			'right': False,
			'down': False,
			'up': False
			}
		

	def make_grid(self, width, height):
		columns = []
		x = 0
		while x < width:
			column = []
			y = 0
			while y < height:
				column.append(False)
				y += 1
			columns.append(column)
			x += 1
		return columns
	
	def initialize(self, file):
		contents = read_file(file)
		lines = contents.split('\n')
		self.width = len(lines[0])
		self.height = len(lines)
		self.grid = self.make_grid(self.width, self.height)
		y = 0
		while y < self.height:
			x = 0
			while x < self.width:
				char = lines[y][x]
				if char == 'x':
					# nonpassable square
					self.grid[x][y] = True
				else:
					# floor
					self.grid[x][y] = False
					if char == '*':
						# Main player starting position
						self.player_x = x * 32 + 16
						self.player_y = y * 24 + 16
				x += 1
			y += 1
	
	def process_input(self, events):
		
		# Keys and the directions they correspond to
		key_mapping = {
			pygame.K_LEFT: 'left',
			pygame.K_RIGHT: 'right',
			pygame.K_UP: 'up',
			pygame.K_DOWN: 'down'
			}
		for event in events:
			if event.type in (pygame.KEYDOWN, pygame.KEYUP):
				keydown = event.type == pygame.KEYDOWN

				#activate pause screen
				if keydown and event.key == pygame.K_RETURN:
					self.next = PauseScene(self)
				#for testing - remove later!
				elif event.key == pygame.K_t:
					self.next = BattleScene()
				else:
					direction_key = key_mapping.get(event.key)
					if direction_key != None:
						self.keys_pressed[direction_key] = keydown
						if keydown:
							self.player_direction = direction_key
		
		# Determine if any of the arrows are being held down. Save the result in self.walking
		self.walking = False
		for pressed in self.keys_pressed.values():
			if pressed:
				self.walking = True
		
	def update(self):
		self.counter += 1
		 
		walk_speed = 4
		new_x = self.player_x
		new_y = self.player_y
		
		if self.keys_pressed['left']:
			new_x -= walk_speed
		elif self.keys_pressed['right']:
			new_x += walk_speed
		if self.keys_pressed['down']:
			new_y += walk_speed
		elif self.keys_pressed['up']:
			new_y -= walk_speed
		
		col = new_x / 40
		row = new_y / 40
		# Player collides into wall?
		if not self.grid[col][row]:
			self.player_x = new_x
			self.player_y = new_y

		# Player switching map screens?
		if self.player_x == 630:
			self.col += 1
			self.player_x = 10
		elif self.player_x == 10:
			self.col -= 1
			self.player_x = 630
		elif self.player_y == 10:
			self.row -= 1
			self.player_y = 470
		elif self.player_y == 470:
			self.row +=1
			self.player_y = 10

		"""
		self.map_key = str(self.row) + '_' + str(self.col)
		self.initialize('maps/level_' + self.map_key + '.txt')
		"""
		

		
	
	def render(self, screen):
                
		screen.fill((0, 0, 0))
		
		# renders background
		overall_background = get_image('images/level_' + self.map_key + '.png')
		screen.blit(overall_background, (0,0))
		
		# Render the background tiles
		y = 0
		while y < self.height:
			x = 0
			while x < self.width:

				#test renders for determining passable/unpassable blocks - to be removed.
				if self.grid[x][y]:
					tile = get_image('images/dirt.png')
					screen.blit(tile, (x * 40, y * 40))


				
				x += 1
			y += 1
		
		

		
		# Render the player
		image = 'images/' + self.player_direction
		if not self.walking:
			image += '0'
		else:
			# use these images in this order if the player is walking
			image += '0102'[(self.counter / 4) % 4]
		image += '.png'

		screen.blit(get_image(image), (self.player_x - 4, self.player_y - 12))

		#renders health count
		health_render = get_text('Health: ' + str(health_count), 36, (255, 0, 0))
		screen.blit(health_render, (440, 20))

def start_game():
	fps = 30
	pygame.init()
	
	screen = pygame.display.set_mode((640, 480))
	
	virtual_screen = pygame.Surface((640, 480))
	
	active_scene = TitleScene()
	health_count = 10
	
	while active_scene != None:
		start = time.time()
		
		events = pygame.event.get()
		
		active_scene.process_input(events)
		active_scene.update()
		active_scene.render(virtual_screen)
		pygame.transform.scale(virtual_screen, (640, 480), screen)
		
		active_scene = active_scene.next
		
		for event in events:
			if event.type == pygame.QUIT:
				active_scene = None 
			if event.type == pygame.KEYDOWN:
				if event.key == pygame.K_ESCAPE:
					active_scene = None 
				elif event.key == pygame.K_F4:
					pressed_keys = pygame.key.get_pressed()
					if pressed_keys[pygame.K_LALT] or pressed_keys[pygame.K_RALT]:
						active_scene = None 
		
		pygame.display.flip()
		
		end = time.time()
		diff = end - start
		delay = 1.0 / fps - diff
		if delay > 0:
			time.sleep(delay)

start_game()


